home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / sendmail.8.8.4.tar.gz / sendmail.8.8.4.tar / sendmail-8.8.4 / rmail / rmail.c < prev   
C/C++ Source or Header  |  1996-11-24  |  10KB  |  374 lines

  1. /*
  2.  * Copyright (c) 1988, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1988, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)rmail.c    8.3 (Berkeley) 5/15/95";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * RMAIL -- UUCP mail server.
  46.  *
  47.  * This program reads the >From ... remote from ... lines that UUCP is so
  48.  * fond of and turns them into something reasonable.  It then execs sendmail
  49.  * with various options built from these lines. 
  50.  *
  51.  * The expected syntax is:
  52.  *
  53.  *     <user> := [-a-z0-9]+
  54.  *     <date> := ctime format
  55.  *     <site> := [-a-z0-9!]+
  56.  * <blank line> := "^\n$"
  57.  *     <from> := "From" <space> <user> <space> <date>
  58.  *          [<space> "remote from" <space> <site>]
  59.  *    <forward> := ">" <from>
  60.  *        msg := <from> <forward>* <blank-line> <body>
  61.  *
  62.  * The output of rmail(8) compresses the <forward> lines into a single
  63.  * from path.
  64.  *
  65.  * The err(3) routine is included here deliberately to make this code
  66.  * a bit more portable.
  67.  */
  68. #include <sys/param.h>
  69. #include <sys/stat.h>
  70. #include <sys/wait.h>
  71.  
  72. #include <ctype.h>
  73. #include <fcntl.h>
  74. #include <paths.h>
  75. #include <stdio.h>
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <sysexits.h>
  79. #include <unistd.h>
  80.  
  81. #ifndef MAX
  82. # define MAX(a, b)    ((a) < (b) ? (b) : (a))
  83. #endif
  84.  
  85. void err __P((int, const char *, ...));
  86. void usage __P((void));
  87.  
  88. int
  89. main(argc, argv)
  90.     int argc;
  91.     char *argv[];
  92. {
  93.     extern char *optarg;
  94.     extern int errno, optind;
  95.     FILE *fp;
  96.     struct stat sb;
  97.     size_t fplen, fptlen, len;
  98.     off_t offset;
  99.     int ch, debug, i, pdes[2], pid, status;
  100.     char *addrp, *domain, *p, *t;
  101.     char *from_path, *from_sys, *from_user;
  102.     char *args[100], buf[2048], lbuf[2048];
  103.  
  104.     debug = 0;
  105.     domain = "UUCP";        /* Default "domain". */
  106.     while ((ch = getopt(argc, argv, "D:T")) != EOF)
  107.         switch (ch) {
  108.         case 'T':
  109.             debug = 1;
  110.             break;
  111.         case 'D':
  112.             domain = optarg;
  113.             break;
  114.         case '?':
  115.         default:
  116.             usage();
  117.         }
  118.     argc -= optind;
  119.     argv += optind;
  120.  
  121.     if (argc < 1)
  122.         usage();
  123.  
  124.     from_path = from_sys = from_user = NULL;
  125.     for (offset = 0;;) {
  126.  
  127.         /* Get and nul-terminate the line. */
  128.         if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
  129.             exit (EX_DATAERR);
  130.         if ((p = strchr(lbuf, '\n')) == NULL)
  131.             err(EX_DATAERR, "line too long");
  132.         *p = '\0';
  133.  
  134.         /* Parse lines until reach a non-"From" line. */
  135.         if (!strncmp(lbuf, "From ", 5))
  136.             addrp = lbuf + 5;
  137.         else if (!strncmp(lbuf, ">From ", 6))
  138.             addrp = lbuf + 6;
  139.         else if (offset == 0)
  140.             err(EX_DATAERR,
  141.                 "missing or empty From line: %s", lbuf);
  142.         else {
  143.             *p = '\n';
  144.             break;
  145.         }
  146.  
  147.         if (*addrp == '\0')
  148.             err(EX_DATAERR, "corrupted From line: %s", lbuf);
  149.  
  150.         /* Use the "remote from" if it exists. */
  151.         for (p = addrp; (p = strchr(p + 1, 'r')) != NULL;)
  152.             if (!strncmp(p, "remote from ", 12)) {
  153.                 for (t = p += 12; *t && !isspace(*t); ++t);
  154.                 *t = '\0';
  155.                 if (debug)
  156.                     (void)fprintf(stderr,
  157.                         "remote from: %s\n", p);
  158.                 break;
  159.             }
  160.  
  161.         /* Else use the string up to the last bang. */
  162.         if (p == NULL)
  163.             if (*addrp == '!')
  164.                 err(EX_DATAERR,
  165.                     "bang starts address: %s", addrp);
  166.             else if ((t = strrchr(addrp, '!')) != NULL) {
  167.                 *t = '\0';
  168.                 p = addrp;
  169.                 addrp = t + 1;
  170.                 if (*addrp == '\0')
  171.                     err(EX_DATAERR,
  172.                         "corrupted From line: %s", lbuf);
  173.                 if (debug)
  174.                     (void)fprintf(stderr, "bang: %s\n", p);
  175.             }
  176.  
  177.         /* 'p' now points to any system string from this line. */
  178.         if (p != NULL) {
  179.             /* Nul terminate it as necessary. */
  180.             for (t = p; *t && !isspace(*t); ++t);
  181.             *t = '\0';
  182.  
  183.             /* If the first system, copy to the from_sys string. */
  184.             if (from_sys == NULL) {
  185.                 if ((from_sys = strdup(p)) == NULL)
  186.                     err(EX_TEMPFAIL, NULL);
  187.                 if (debug)
  188.                     (void)fprintf(stderr,
  189.                         "from_sys: %s\n", from_sys);
  190.             }
  191.  
  192.             /* Concatenate to the path string. */
  193.             len = t - p;
  194.             if (from_path == NULL) {
  195.                 fplen = 0;
  196.                 if ((from_path = malloc(fptlen = 256)) == NULL)
  197.                     err(EX_TEMPFAIL, NULL);
  198.             }
  199.             if (fplen + len + 2 > fptlen) {
  200.                 fptlen += MAX(fplen + len + 2, 256);
  201.                 if ((from_path =
  202.                     realloc(from_path, fptlen)) == NULL)
  203.                     err(EX_TEMPFAIL, NULL);
  204.             }
  205.             memmove(from_path + fplen, p, len);
  206.             fplen += len;
  207.             from_path[fplen++] = '!';
  208.             from_path[fplen] = '\0';
  209.         }
  210.  
  211.         /* Save off from user's address; the last one wins. */
  212.         for (p = addrp; *p && !isspace(*p); ++p);
  213.         *p = '\0';
  214.         if (*addrp == '\0')
  215.             addrp = "<>";
  216.         if (from_user != NULL)
  217.             free(from_user);
  218.         if ((from_user = strdup(addrp)) == NULL)
  219.             err(EX_TEMPFAIL, NULL);
  220.  
  221.         if (debug) {
  222.             if (from_path != NULL)
  223.                 (void)fprintf(stderr,
  224.                     "from_path: %s\n", from_path);
  225.             (void)fprintf(stderr, "from_user: %s\n", from_user);
  226.         }
  227.  
  228.         if (offset != -1)
  229.             offset = (off_t)ftell(stdin);
  230.     }
  231.  
  232.     i = 0;
  233.     args[i++] = _PATH_SENDMAIL;    /* Build sendmail's argument list. */
  234.     args[i++] = "-oee";        /* No errors, just status. */
  235.     args[i++] = "-odq";        /* Queue it, don't try to deliver. */
  236.     args[i++] = "-oi";        /* Ignore '.' on a line by itself. */
  237.  
  238.     /* set from system and protocol used */
  239.     if (from_sys == NULL)
  240.         (void)snprintf(buf, sizeof(buf), "-p%s", domain);
  241.     else if (strchr(from_sys, '.') == NULL)
  242.         (void)snprintf(buf, sizeof(buf), "-p%s:%s.%s",
  243.             domain, from_sys, domain);
  244.     else
  245.         (void)snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
  246.     if ((args[i++] = strdup(buf)) == NULL)
  247.         err(EX_TEMPFAIL, NULL);
  248.  
  249.                     /* Set name of ``from'' person. */
  250.     (void)snprintf(buf, sizeof(buf), "-f%s%s",
  251.         from_path ? from_path : "", from_user);
  252.     if ((args[i++] = strdup(buf)) == NULL)
  253.         err(EX_TEMPFAIL, NULL);
  254.  
  255.     /*
  256.      * Don't copy arguments beginning with - as they will be
  257.      * passed to sendmail and could be interpreted as flags.
  258.      * To prevent confusion of sendmail wrap < and > around
  259.      * the address (helps to pass addrs like @gw1,@gw2:aa@bb)
  260.      */
  261.     while (*argv) {
  262.         if (**argv == '-')
  263.             err(EX_USAGE, "dash precedes argument: %s", *argv);
  264.         if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
  265.             args[i++] = *argv;
  266.         else {
  267.             if ((args[i] = malloc(strlen(*argv) + 3)) == NULL)
  268.                 err(EX_TEMPFAIL, "Cannot malloc");
  269.             sprintf (args [i++], "<%s>", *argv);
  270.         }
  271.         argv++;
  272.     } 
  273.     args[i] = 0;
  274.  
  275.     if (debug) {
  276.         (void)fprintf(stderr, "Sendmail arguments:\n");
  277.         for (i = 0; args[i]; i++)
  278.             (void)fprintf(stderr, "\t%s\n", args[i]);
  279.     }
  280.  
  281.     /*
  282.      * If called with a regular file as standard input, seek to the right
  283.      * position in the file and just exec sendmail.  Could probably skip
  284.      * skip the stat, but it's not unreasonable to believe that a failed
  285.      * seek will cause future reads to fail.
  286.      */
  287.     if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) {
  288.         if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
  289.             err(EX_TEMPFAIL, "stdin seek");
  290.         execv(_PATH_SENDMAIL, args);
  291.         err(EX_OSERR, "%s", _PATH_SENDMAIL);
  292.     }
  293.  
  294.     if (pipe(pdes) < 0)
  295.         err(EX_OSERR, NULL);
  296.  
  297.     switch (pid = vfork()) {
  298.     case -1:                /* Err. */
  299.         err(EX_OSERR, NULL);
  300.     case 0:                    /* Child. */
  301.         if (pdes[0] != STDIN_FILENO) {
  302.             (void)dup2(pdes[0], STDIN_FILENO);
  303.             (void)close(pdes[0]);
  304.         }
  305.         (void)close(pdes[1]);
  306.         execv(_PATH_SENDMAIL, args);
  307.         _exit(127);
  308.         /* NOTREACHED */
  309.     }
  310.  
  311.     if ((fp = fdopen(pdes[1], "w")) == NULL)
  312.         err(EX_OSERR, NULL);
  313.     (void)close(pdes[0]);
  314.  
  315.     /* Copy the file down the pipe. */
  316.     do {
  317.         (void)fprintf(fp, "%s", lbuf);
  318.     } while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
  319.  
  320.     if (ferror(stdin))
  321.         err(EX_TEMPFAIL, "stdin: %s", strerror(errno));
  322.  
  323.     if (fclose(fp))
  324.         err(EX_OSERR, NULL);
  325.  
  326.     if ((waitpid(pid, &status, 0)) == -1)
  327.         err(EX_OSERR, "%s", _PATH_SENDMAIL);
  328.  
  329.     if (!WIFEXITED(status))
  330.         err(EX_OSERR,
  331.             "%s: did not terminate normally", _PATH_SENDMAIL);
  332.  
  333.     if (WEXITSTATUS(status))
  334.         err(status, "%s: terminated with %d (non-zero) status",
  335.             _PATH_SENDMAIL, WEXITSTATUS(status));
  336.     exit(EX_OK);
  337. }
  338.  
  339. void
  340. usage()
  341. {
  342.     (void)fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
  343.     exit(EX_USAGE);
  344. }
  345.  
  346. #ifdef __STDC__
  347. #include <stdarg.h>
  348. #else
  349. #include <varargs.h>
  350. #endif
  351.  
  352. void
  353. #ifdef __STDC__
  354. err(int eval, const char *fmt, ...)
  355. #else
  356. err(eval, fmt, va_alist)
  357.     int eval;
  358.     const char *fmt;
  359.     va_dcl
  360. #endif
  361. {
  362.     va_list ap;
  363. #if __STDC__
  364.     va_start(ap, fmt);
  365. #else
  366.     va_start(ap);
  367. #endif
  368.     (void)fprintf(stderr, "rmail: ");
  369.     (void)vfprintf(stderr, fmt, ap);
  370.     va_end(ap);
  371.     (void)fprintf(stderr, "\n");
  372.     exit(eval);
  373. }
  374.